package com.candoit.webapps.pricing.util;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;

import org.apache.myfaces.custom.fileupload.UploadedFile;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.transaction.annotation.Transactional;

import com.candoit.webapps.pricing.bean.PricingContext;
import com.candoit.webapps.pricing.model.Categoria;
import com.candoit.webapps.pricing.model.CategoriaCuenta;
import com.candoit.webapps.pricing.model.CentroCostos;
import com.candoit.webapps.pricing.model.CriterioDistribucion;
import com.candoit.webapps.pricing.model.Cuenta;
import com.candoit.webapps.pricing.model.CuentaMes;
import com.candoit.webapps.pricing.model.CuentasMesFK;
import com.candoit.webapps.pricing.model.MateriaPrima;
import com.candoit.webapps.pricing.model.TipoLinea;
import com.candoit.webapps.pricing.model.TipoMateriaPrima;

public class ImportExcelUtil {

	private static ImportExcelUtil instance = null;
	
	public static ImportExcelUtil getInstance(){
		if (instance == null ){
			instance = new ImportExcelUtil();
		}
		
		return instance;
	}
	
	public boolean importarCuentas(UploadedFile archivo){
		POIFSFileSystem fs = null;
		try {
			fs = new POIFSFileSystem(archivo.getInputStream());
		} catch (Exception e) {
			FacesContext.getCurrentInstance().addMessage("cuentasform:botonImportar", new FacesMessage("Formato no permitido. Tiene que ser con extensiÃ³n xls"));
			return false;
		} 
		HSSFWorkbook wb = null;
		try {
			wb = new HSSFWorkbook(fs);
		} catch (Exception e) {
			FacesContext.getCurrentInstance().addMessage("cuentasform:botonImportar", new FacesMessage("Error al leer el archivo"));
			return false;
		}   
		Sheet sheet =  wb.getSheet("I - CUENTAS");
		if (sheet != null){
			HSSFFormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator(wb);
			int rows = sheet.getLastRowNum();
			for (int i = 0; i < sheet.getLastRowNum(); i++) {
				 if (
						 	(!sheet.getRow(i).getCell(0).getStringCellValue().equals(""))
						 &&
						 	(!sheet.getRow(i).getCell(0).getStringCellValue().startsWith("TOTAL")) 
						 && 
						 	(
									sheet.getRow(i).getCell(1).getCellType() == Cell.CELL_TYPE_NUMERIC
								||
									sheet.getRow(i).getCell(1).getCellType() == Cell.CELL_TYPE_FORMULA
								||
									(sheet.getRow(i).getCell(1) == null)
								||
									sheet.getRow(i).getCell(1).getCellType()  == Cell.CELL_TYPE_BLANK
							)
					){
					 String cuentaNombre = sheet.getRow(i).getCell(0).getStringCellValue();
	
					 if (sheet.getRow(i).getCell(2) != null){
						 String categoriaNombre = sheet.getRow(i).getCell(2).getStringCellValue();
						 CategoriaCuenta categoria = QueryUtil.getInstance().getCategoriaByDesc(categoriaNombre);
						 if (categoria != null){
							 Cuenta cuenta = null;
							 cuenta = QueryUtil.getInstance().getCuentaByCategoria(cuentaNombre,categoria);
							 if (cuenta == null){
								 cuenta = new Cuenta();
								 cuenta.setDescripcion(cuentaNombre);
								 cuenta.setCategoria(categoria);
								 this.save(cuenta);
							 }
							 double costo = 0.00d;
							 Cell valor = sheet.getRow(i).getCell(1);
							 if (valor != null ){
								 if (valor.getCellType() == Cell.CELL_TYPE_FORMULA){
									 costo = formulaEvaluator.evaluate(valor).getNumberValue();
								 }else{
									 costo = sheet.getRow(i).getCell(1).getNumericCellValue();
								 }
							 }	
							 
							 Calendar cal = new GregorianCalendar();
							 Date fechaActual = new Date();
							 cal.setTime(fechaActual);
							 Integer mesActual = cal.get(Calendar.MONTH);
							 
							 CuentaMes cuentaMes = QueryUtil.getInstance().getUltimaCuenta(cuenta);
							 if (cuentaMes != null){
								 cuentaMes.setCosto(costo);
								 cuentaMes.setCostoSimulado(costo);
								 this.update(cuentaMes);
							 }else{
								 CuentasMesFK fk = new CuentasMesFK();
								 fk.setCuenta(cuenta);
								 fk.setFecha(fechaActual());
								 cuentaMes = new CuentaMes();
								 cuentaMes.setCuentaMesFK(fk);
								 cuentaMes.setCosto(costo);
								 cuentaMes.setCostoSimulado(costo);
								 this.save(cuentaMes);
							 } 	 
						 }
					 }
				 }	 
		 }
		return true;
	  }else{
			FacesContext.getCurrentInstance().addMessage("cuentasform:botonImportar", new FacesMessage("No encontrÃ³ la hoja de calculo con nombre 'I - CUENTAS'"));
			return false;
		}	
	}
	
	/*Devuelve Año - mes - dia primero - cero horas*/
	public static Long fechaActual(){
		return MyTime.getFirstDayOfThisMonth();
	}
	
	private Integer getRowForCC(CentroCostos cc){
		Integer id = cc.getId();
		boolean ex = (id == 25)|(id == 26)|(id == 29)|(id == 30)|(id == 36)|(id == 34);
		return ex? 58 : 57;
	}
	
	public boolean importarCuentasManoDeObra(UploadedFile archivo){
		POIFSFileSystem fs = null;
		try {
			fs = new POIFSFileSystem(archivo.getInputStream());
		} catch (Exception e) {
			FacesContext.getCurrentInstance().addMessage("cuentasform:botonImportar", new FacesMessage("Formato no permitido. Tiene que ser con extensiÃ³n xls"));
			return false;
		} 
		HSSFWorkbook wb = null;
		try {
			org.apache.poi.hssf.record.crypto.Biff8EncryptionKey.setCurrentUserPassword("SECOSO");
			wb = new HSSFWorkbook(fs);
		} catch (Exception e) {
			FacesContext.getCurrentInstance().addMessage("cuentasform:botonImportar", new FacesMessage("Error al leer el archivo"));
			return false;
		}
		
		List<CentroCostos> productivos = QueryUtil.getInstance().getCentroCostosByCategoria(Categoria.PRODUCTION_CODE);
		Calendar cal = new GregorianCalendar();
		Date fechaActual = new Date();
		cal.setTime(fechaActual);
		Integer mesActual = cal.get(Calendar.MONTH);
		for (CentroCostos prod : productivos){
			Double totalCentro = 0.00d;
			boolean saltarPorCuentaUnaSolaFila = false;
			for (int i = 1; i < 8; i++) {
				Sheet sheet =  wb.getSheet(prod.getNombre().toUpperCase() + " " + i);
				if (sheet == null){
					sheet =  wb.getSheet(prod.getNombre().toUpperCase());
					saltarPorCuentaUnaSolaFila = true;
				}
				if (sheet != null){
					try {
						Integer row = getRowForCC(prod);
						Double costo = sheet.getRow(row).getCell(2).getNumericCellValue();
						System.out.println("Hoja: "+ sheet.getSheetName() + "Costo: "+ costo );
						totalCentro = totalCentro + costo;
						if (saltarPorCuentaUnaSolaFila){
							i=8;
						}
					} catch (Exception e) {
						FacesContext.getCurrentInstance().addMessage("cuentasform:botonImportar", new FacesMessage("Error al leer el archivo"));
						return false;
					}	
				}
			}
			
		 this.saveCuentaMO(prod, mesActual, totalCentro); 	 
		}
		
		List<CentroCostos> paraProd = QueryUtil.getInstance().getCentroCostosByCategoria(Categoria.SERVICES_CODE);
		for (CentroCostos pProd : paraProd){
			Sheet sheet =  wb.getSheet(pProd.getNombre().toUpperCase());
			if (sheet != null){
				try {	
					Integer row = getRowForCC(pProd);
					Double costo = sheet.getRow(row).getCell(2).getNumericCellValue();
					System.out.println("Hoja: "+ sheet.getSheetName() + "Costo: "+ costo );
					this.saveCuentaMO(pProd, mesActual, costo);
				} catch (Exception e) {
					FacesContext.getCurrentInstance().addMessage("cuentasform:botonImportar", new FacesMessage("Error al leer el archivo"));
					return false;
				}	
			}
		}
		
		List<CentroCostos> sinAsig = QueryUtil.getInstance().getCentroCostosByCategoria(Categoria.SIN_ASIGNAR_CODE);
		for (CentroCostos sinA : sinAsig){
			Sheet sheet =  wb.getSheet(sinA.getNombre().toUpperCase());
			if (sheet != null){
				try{	
					Integer row = getRowForCC(sinA);
					Double costo = sheet.getRow(row).getCell(2).getNumericCellValue();
					System.out.println("Hoja: "+ sheet.getSheetName() + "Costo: "+ costo );
					this.saveCuentaMO(sinA, mesActual, costo);
				} catch (Exception e) {
					FacesContext.getCurrentInstance().addMessage("cuentasform:botonImportar", new FacesMessage("Error al leer el archivo"));
					return false;
				}	
			}
		}
		return true;
	}

	/*
	public boolean importarMaterias(UploadedFile archivo){
		try {
			POIFSFileSystem fs = new POIFSFileSystem(archivo.getInputStream()); 
			HSSFWorkbook  wb =new HSSFWorkbook(fs);
			Sheet sheet =  wb.getSheet("COSTOS M.P.");
			if (sheet != null){
			  for (int i = 2; i < sheet.getLastRowNum()-1; i++) {
				if (sheet.getRow(i) != null && sheet.getRow(i).getCell(0) != null && sheet.getRow(i).getCell(0).getStringCellValue() != null
						&& !sheet.getRow(i).getCell(0).getStringCellValue().equals("") 
						&& (sheet.getRow(i).getCell(4) != null )
						&& (sheet.getRow(i).getCell(4).getCellType() != Cell.CELL_TYPE_BLANK )
						&& (sheet.getRow(i).getCell(4).getCellType() == Cell.CELL_TYPE_NUMERIC || sheet.getRow(i).getCell(4).getCellType() == Cell.CELL_TYPE_FORMULA )){
					String cuentaNombre = sheet.getRow(i).getCell(0).getStringCellValue().trim();
					double costo = sheet.getRow(i).getCell(4).getNumericCellValue();
					String descTipo = sheet.getRow(i).getCell(5).getStringCellValue();
					TipoMateriaPrima tipo = QueryUtil.getInstance().getTipoMateriaPrimaByDesc(descTipo);
					if (tipo != null){
						MateriaPrima materia = null;
						try{	
							materia = QueryUtil.getInstance().getMateriaByDescriptionAndTipo(cuentaNombre, tipo);
						}catch(Exception e){}
						if (materia == null){
							materia = new MateriaPrima();
							materia.setNombre(cuentaNombre);
							materia.setCostoUnitario(costo);
							materia.setCostoSimulado(costo);
							materia.setTipoMateriaPrima(tipo);
							this.save(materia);
						}else{
					 		materia.setCostoUnitario(costo);
					 		materia.setCostoSimulado(costo);
					 		this.update(materia);
					 	}
				 }
			 }
		  }
		return true;	  
   }else{
	   FacesContext.getCurrentInstance().addMessage("abmmatprimform:botonImportar", new FacesMessage("No encontrÃ³ la hoja de calculo con nombre 'COSTOS M.P.'"));
		return false;
   }

	} catch (Exception e) {
		FacesContext.getCurrentInstance().addMessage("abmmatprimform:botonImportar", new FacesMessage("Error al importar los datos"));
		return false;
	}
}
*/
	
	public boolean importarMaterias(UploadedFile archivo){
		try {
			POIFSFileSystem fs = new POIFSFileSystem(archivo.getInputStream()); 
			HSSFWorkbook  wb =new HSSFWorkbook(fs);
			Sheet sheetIndustrial =  wb.getSheet("COSTOS M.P.");
			if (sheetIndustrial != null){
				readMPFromSheet(sheetIndustrial,TipoLinea.INDUSTRIAL);
		   }else{
			   FacesContext.getCurrentInstance().
			   			addMessage(
			   						"abmmatprimform:botonImportar", 
			   						new FacesMessage("No se encontro la hoja de calculo con nombre 'COSTOS M.P.'")
			   						);
				return false;
		   }
			
			Sheet sheetArtesanal =  wb.getSheet("COSTOS M.P. ARTESANAL");
			if (sheetArtesanal != null){
				readMPFromSheet(sheetArtesanal,TipoLinea.ARTESANAL);
		   }else{
			   FacesContext.getCurrentInstance().
			   			addMessage(
			   						"abmmatprimform:botonImportar", 
			   						new FacesMessage("No se encontro la hoja de calculo con nombre 'COSTOS M.P. ARTESANAL'")
			   						);
				return false;
		   }
		return true;

	} catch (Exception e) {
		FacesContext.getCurrentInstance().addMessage("abmmatprimform:botonImportar", new FacesMessage("Error al importar los datos"));
		return false;
	}
}
	public void readMPFromSheet(Sheet sheet, Integer tipoLinea){
		for (int i = 2; i <= sheet.getLastRowNum()+1; i++) {
			if (sheet.getRow(i) != null && sheet.getRow(i).getCell(0) != null && sheet.getRow(i).getCell(0).getStringCellValue() != null
					&& !sheet.getRow(i).getCell(0).getStringCellValue().equals("") 
					&& (sheet.getRow(i).getCell(4) != null )
					&& (sheet.getRow(i).getCell(4).getCellType() != Cell.CELL_TYPE_BLANK )
					&& (sheet.getRow(i).getCell(4).getCellType() == Cell.CELL_TYPE_NUMERIC || sheet.getRow(i).getCell(4).getCellType() == Cell.CELL_TYPE_FORMULA )){
				String cuentaNombre = sheet.getRow(i).getCell(0).getStringCellValue().trim();
				double costo = sheet.getRow(i).getCell(4).getNumericCellValue();
				String descTipo = sheet.getRow(i).getCell(5).getStringCellValue();
				TipoMateriaPrima tipo = QueryUtil.getInstance().getTipoMateriaPrimaByDescAndTipoLinea(descTipo,tipoLinea);
				if (tipo != null){
					MateriaPrima materia = null;
					try{	
						materia = QueryUtil.getInstance().getMateriaByDescriptionAndTipo(cuentaNombre, tipo);
					}catch(Exception e){}
					if (materia == null){
						materia = new MateriaPrima();
						materia.setNombre(cuentaNombre);
						materia.setCostoUnitario(costo);
						materia.setCostoSimulado(costo);
						materia.setTipoMateriaPrima(tipo);
						this.save(materia);
					}else{
				 		materia.setCostoUnitario(costo);
				 		materia.setCostoSimulado(costo);
				 		this.update(materia);
				 	}
			 }
		 }
	  }
	}
	
	@Transactional
	public void save(Object o){
		EntityManager em = PricingContext.getInstance().getEntityManager();
		em.persist(o);
		if (!em.getTransaction().isActive()){
			em.getTransaction().begin();
		}	
		em.getTransaction().commit();
	}
	
	@Transactional
	public void update(Object o){
		EntityManager em = PricingContext.getInstance().getEntityManager();
		em.merge(o);
		if (!em.getTransaction().isActive()){
			em.getTransaction().begin();
		}	
		em.getTransaction().commit();
	}
	
	private void saveCuentaMO(CentroCostos centro, Integer mesActual, Double costo){
		 Cuenta cuenta = null;
		 cuenta = QueryUtil.getInstance().getCuentaByDescription("MANO DE OBRA",centro);
		 if (cuenta == null){
			 cuenta = new Cuenta();
			 cuenta.setDescripcion("MANO DE OBRA");
			 cuenta.setCentro(centro);
			 CriterioDistribucion criterio = QueryUtil.getInstance().getCriterioDistribucionById(CriterioDistribucion.DIRECTA_CODE);
			 cuenta.setCriterio(criterio);
			 this.save(cuenta);
		 }
		 
		 CuentaMes cuentaMes = QueryUtil.getInstance().getUltimaCuenta(cuenta);
		 if (cuentaMes != null){
			 cuentaMes.setCosto(costo);
			 cuentaMes.setCostoSimulado(costo);
			 this.update(cuentaMes);
		 }else{
			 CuentasMesFK fk = new CuentasMesFK();
			 fk.setCuenta(cuenta);
			 fk.setFecha(fechaActual());
			 cuentaMes = new CuentaMes();
			 cuentaMes.setCuentaMesFK(fk);
			 cuentaMes.setCosto(costo);
			 cuentaMes.setCostoSimulado(costo);
			 this.save(cuentaMes);
		 } 	 
	}
}